/*
 * Copyright (c) 2010, okazoh_tk. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "alkes/gfx/RectangleShape.h"
#include <memory.h>

namespace alkes {

RectangleShape::RectangleShape(uint32_t num)
: Shape(num)
{
    Rectangle* rect = rectangles_.initialize(num);
    if (rect)
    {
        memset(rect, 0, num * sizeof(Rectangle));
        setDirty(true);
    }
}

RectangleShape::~RectangleShape()
{
}

const RectangleShape::Rectangle& RectangleShape::getRectangle(uint32_t index) const
{
    return rectangles_[index];
}

const Rect RectangleShape::getRect(uint32_t index) const
{
    AL_PRE_COND(validate(index), Rect::ZERO);

    return rectangles_[index].rect;
}

const Color RectangleShape::getColor(uint32_t index) const
{
    return getColor0(index);
}

const Color RectangleShape::getColor0(uint32_t index) const
{
    AL_PRE_COND(validate(index), Color::BLACK);

    return rectangles_[index].color0;
}

const Color RectangleShape::getColor1(uint32_t index) const
{
    AL_PRE_COND(validate(index), Color::BLACK);

    return rectangles_[index].color1;
}

bool RectangleShape::isLine(uint32_t index) const
{
    AL_PRE_COND(validate(index), false);

    return rectangles_[index].isLine();
}

bool RectangleShape::isGradient(uint32_t index) const
{
    AL_PRE_COND(validate(index), false);

    return rectangles_[index].isGradient();
}

bool RectangleShape::isHorizontalGradient(uint32_t index) const
{
    AL_PRE_COND(validate(index), false);

    return rectangles_[index].isHorizontalGradient();
}

void RectangleShape::setFillRectangle(const Rect& rect, const Color& color)
{
    setFillRectangle(0, rect, color);
}

void RectangleShape::setGradientFillRectangle(const Rect& rect, const Color& color0, const Color& color1, bool horizontal)
{
    setGradientFillRectangle(0, rect, color0, color1, horizontal);
}

void RectangleShape::setLineRectangle(const Rect& rect, const Color& color)
{
    setLineRectangle(0, rect, color);
}

void RectangleShape::setRect(const Rect& rect)
{
    setRect(0, rect);
}

void RectangleShape::setColor(const Color& color)
{
    setColor(0, color);
}

void RectangleShape::setLineMode(bool is_line)
{
    setLineMode(0, is_line);
}

void RectangleShape::setGradientColor(const Color& color0, const Color& color1)
{
    setGradientColor(0, color0, color1);
}

void RectangleShape::setGradientOrder(bool horizontal)
{
    setGradientOrder(0, horizontal);
}

void RectangleShape::setFillRectangle(uint32_t index, const Rect& rect, const Color& color)
{
    setLineMode(index, false);
    setRect(index, rect);
    setColor(index, color);
}

void RectangleShape::setGradientFillRectangle(uint32_t index, const Rect& rect, const Color& color0, const Color& color1, bool horizontal)
{
    setLineMode(index, false);
    setRect(index, rect);
    setGradientColor(index, color0, color1);
    setGradientOrder(index, horizontal);
}

void RectangleShape::setLineRectangle(uint32_t index, const Rect& rect, const Color& color)
{
    setLineMode(index, true);
    setRect(index, rect);
    setColor(index, color);
}

void RectangleShape::setRect(uint32_t index, const Rect& rect)
{
    AL_PRE_COND(validate(index), );

    if (rectangles_[index].rect != rect)
    {
        rectangles_[index].rect = rect;
        setDirty(true);
    }
}

void RectangleShape::setColor(uint32_t index, const Color& color)
{
    AL_PRE_COND(validate(index), );

    if (rectangles_[index].color0 != color)
    {
        rectangles_[index].color0 = color;
        setDirty(true);
    }

    if (rectangles_[index].color1 != color)
    {
        rectangles_[index].color1 = color;
        setDirty(true);
    }

    if (false != rectangles_[index].isGradient())
    {
        rectangles_[index].setGradient(false);
        setDirty(true);
    }
}

void RectangleShape::setLineMode(uint32_t index, bool is_line)
{
    AL_PRE_COND(validate(index), );

    if (is_line != rectangles_[index].isLine())
    {
        rectangles_[index].setLine(is_line);
        setDirty(true);
    }
}

void RectangleShape::setGradientColor(uint32_t index, const Color& color0, const Color& color1)
{
    AL_PRE_COND(validate(index), );

    if (rectangles_[index].color0 != color0)
    {
        rectangles_[index].color0 = color0;
        setDirty(true);
    }

    if (rectangles_[index].color1 != color1)
    {
        rectangles_[index].color1 = color1;
        setDirty(true);
    }

    if (false == rectangles_[index].isGradient())
    {
        rectangles_[index].setGradient(true);
        setDirty(true);
    }
}

void RectangleShape::setGradientOrder(uint32_t index, bool horizontal)
{
    AL_PRE_COND(validate(index), );

    if (horizontal != rectangles_[index].isHorizontalGradient())
    {
        rectangles_[index].setGradientOrder(horizontal);
        setDirty(true);
    }
}

void RectangleShape::Rectangle::setLine(bool is_line)
{
    if (is_line)
        flags |= FLAG_LINE_MODE;
    else
        flags &= (~(uint8_t)FLAG_LINE_MODE);
}

void RectangleShape::Rectangle::setGradient(bool is_gradient)
{
    if (is_gradient)
        flags |= FLAG_GRADIENT;
    else
        flags &= (~(uint8_t)FLAG_GRADIENT);
}

void RectangleShape::Rectangle::setGradientOrder(bool horizontal)
{
    if (horizontal)
        flags |= FLAG_GRADIENT_ORDER;
    else
        flags &= (~(uint8_t)FLAG_GRADIENT_ORDER);
}

bool RectangleShape::Rectangle::isLine() const
{
    return 0 != (flags & FLAG_LINE_MODE);
}

bool RectangleShape::Rectangle::isGradient() const
{
    return 0 != (flags & FLAG_GRADIENT);
}

bool RectangleShape::Rectangle::isHorizontalGradient() const
{
    return 0 != (flags & FLAG_GRADIENT_ORDER);
}

}
